package org.chartsy.bollingerbands; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Rectangle; import java.text.DecimalFormat; import java.util.LinkedHashMap; import org.chartsy.main.ChartFrame; import org.chartsy.main.chart.Overlay; import org.chartsy.main.data.DataItem; import org.chartsy.main.data.Dataset; import org.chartsy.main.utils.DefaultPainter; import org.chartsy.main.utils.Range; import org.chartsy.main.utils.SerialVersion; import org.openide.nodes.AbstractNode; /** * * @author viorel.gheba */ public class BollingerBands extends Overlay { private static final long serialVersionUID = SerialVersion.APPVERSION; public static final String FULL_NAME = "Bollinger Bands"; public static final String UPPER = "upper"; public static final String MIDDLE = "middle"; public static final String LOWER = "lower"; private OverlayProperties properties; public BollingerBands() { super(); properties = new OverlayProperties(); } public String getName(){ return FULL_NAME; } public String getLabel() { return properties.getLabel() + " (" + properties.getPrice() + ", " + properties.getStd() + ", " + properties.getPeriod() + ")"; } public Overlay newInstance(){ return new BollingerBands(); } public LinkedHashMap getHTML(ChartFrame cf, int i) { LinkedHashMap ht = new LinkedHashMap(); DecimalFormat df = new DecimalFormat("#,##0.00"); double[] values = getValues(cf, i); String[] labels = {"Upper Band:", "Middle Band:", "Lower Band:"}; ht.put(getLabel(), " "); if (values.length > 0) { Color[] colors = getColors(); for (int j = 0; j < values.length; j++) { ht.put(getFontHTML(colors[j], labels[j]), getFontHTML(colors[j], df.format(values[j]))); } } return ht; } public void paint(Graphics2D g, ChartFrame cf, Rectangle bounds) { Dataset middle = visibleDataset(cf, MIDDLE); Dataset upper = visibleDataset(cf, UPPER); Dataset lower = visibleDataset(cf, LOWER); if (middle != null && upper != null && lower != null) { String price = properties.getPrice(); Range range = cf.getSplitPanel().getChartPanel().getRange(); if (properties.getInsideVisibility()) DefaultPainter.insideFill(g, cf, range, bounds, upper, lower, properties.getInsideTransparentColor(), Dataset.getPrice(price)); DefaultPainter.line(g, cf, range, bounds, middle, properties.getMiddleColor(), properties.getMiddleStroke(), Dataset.getPrice(price)); // paint middle line DefaultPainter.line(g, cf, range, bounds, upper, properties.getUpperColor(), properties.getUpperStroke(), Dataset.getPrice(price)); // paint upper line DefaultPainter.line(g, cf, range, bounds, lower, properties.getLowerColor(), properties.getLowerStroke(), Dataset.getPrice(price)); // paint lower line } } public void calculate() { int period = properties.getPeriod(); int stddev = properties.getStd(); Dataset initial = getDataset(); if (initial != null && !initial.isEmpty()) { Dataset middle = Dataset.SMA(initial, period); addDataset(MIDDLE, middle); Dataset upper = getLowerUpperDataset(initial, middle, period, stddev, UPPER); addDataset(UPPER, upper); Dataset lower = getLowerUpperDataset(initial, middle, period, stddev, LOWER); addDataset(LOWER, lower); } } private Dataset getLowerUpperDataset(final Dataset initial, final Dataset middle, final int period, final int stddev, final String type) { int count = initial.getItemsCount(); Dataset d = Dataset.EMPTY(count); for (int i = period; i < count; i++) { double opendev = 0; double highdev = 0; double lowdev = 0; double closedev = 0; for (int j = 0; j < period; j++) { opendev += Math.pow(initial.getOpenAt(i-j) - middle.getOpenAt(i), 2); highdev += Math.pow(initial.getHighAt(i-j) - middle.getHighAt(i), 2); lowdev += Math.pow(initial.getLowAt(i-j) - middle.getLowAt(i), 2); closedev += Math.pow(initial.getCloseAt(i-j) - middle.getCloseAt(i), 2); } opendev = stddev * Math.sqrt(opendev / period); highdev = stddev * Math.sqrt(highdev / period); lowdev = stddev * Math.sqrt(lowdev / period); closedev = stddev * Math.sqrt(closedev / period); if (type.equals(LOWER)) d.setDataItem(i, new DataItem(middle.getTimeAt(i), middle.getOpenAt(i) - opendev, middle.getHighAt(i) - highdev, middle.getLowAt(i) - lowdev, middle.getCloseAt(i) - closedev, 0)); else d.setDataItem(i, new DataItem(middle.getTimeAt(i), middle.getOpenAt(i) + opendev, middle.getHighAt(i) + highdev, middle.getLowAt(i) + lowdev, middle.getCloseAt(i) + closedev, 0)); } return d; } public Color[] getColors() { return new Color[] {properties.getUpperColor(), properties.getMiddleColor(), properties.getLowerColor()}; } public double[] getValues(ChartFrame cf) { Dataset middle = visibleDataset(cf, MIDDLE); Dataset upper = visibleDataset(cf, UPPER); Dataset lower = visibleDataset(cf, LOWER); int i = middle.getLastIndex(); double[] values = new double[3]; values[0] = upper.getDataItem(i) != null ? upper.getCloseAt(i) : 0; values[1] = middle.getDataItem(i) != null ? middle.getCloseAt(i) : 0; values[2] = lower.getDataItem(i) != null ? lower.getCloseAt(i) : 0; return values; } public double[] getValues(ChartFrame cf, int i) { Dataset middle = visibleDataset(cf, MIDDLE); Dataset upper = visibleDataset(cf, UPPER); Dataset lower = visibleDataset(cf, LOWER); double[] values = new double[3]; values[0] = upper.getDataItem(i) != null ? upper.getCloseAt(i) : 0; values[1] = middle.getDataItem(i) != null ? middle.getCloseAt(i) : 0; values[2] = lower.getDataItem(i) != null ? lower.getCloseAt(i) : 0; return values; } public boolean getMarkerVisibility() { return properties.getMarker(); } public AbstractNode getNode() { return new OverlayNode(properties); } public String getPrice() { return properties.getPrice(); } }